package com.wzh.bigfileupload.service.impl;


import com.wzh.bigfileupload.form.FileForm;
import com.wzh.bigfileupload.service.UploadFileService;
import com.wzh.bigfileupload.utils.FileMd5Util;
import com.wzh.bigfileupload.utils.NameUtil;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;


@Service
public class UploadFileServiceImpl implements UploadFileService {


    @Override
    public Map<String, Object> realUpload(FileForm form, MultipartFile multipartFile) throws Exception {
        String action = form.getAction();
        String fileId = form.getUuid();
        int index = Integer.parseInt(form.getIndex());  //当前是第几片
        String partMd5 = form.getPartMd5();
        int total = Integer.parseInt(form.getTotal()); //总片数
        String fileName = form.getName();
        String size = form.getSize();
        String saveDirectory = form.getSaveDirectory();
        String suffix = NameUtil.getExtensionName(fileName);

//        String saveDirectory =  "C:/Users/William/Desktop/1";
//        String filePath = saveDirectory + "/" + fileId + "." + suffix;
        //验证路径是否存在，不存在则创建目录
        File path = new File(saveDirectory);
        if (!path.exists()) {
            path.mkdirs();
        }
        //文件分片位置
        File file = new File(saveDirectory, fileId + "_" + index);



        //check:校验分片是否上传过; upload:直接上传分片
        Map<String, Object> map = null;
        if ("check".equals(action)) {
            String md5Str = FileMd5Util.getFileMD5(file);
            if (md5Str != null && md5Str.length() == 31) {
                md5Str = "0" + md5Str;
            }
            if (md5Str != null && md5Str.equals(partMd5)) {
                //分片已上传过
                map = new HashMap<>();
                map.put("flag", "1");
                map.put("fileId", fileId);
                if (index != total)
                    return map;
            } else {
                //分片未上传
                map = new HashMap<>();
                map.put("flag", "0");
                map.put("fileId", fileId);
                return map;
            }
        } else if ("upload".equals(action)) {
            //分片上传过程中出错,有残余时需删除分块后,重新上传
            if (file.exists()) {
                file.delete();
            }
//            multipartFile.transferTo(new File(saveDirectory, fileId + "_" + index));
            FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), new File(saveDirectory, fileId + "_" + index));
            map = new HashMap<>();
            map.put("flag", "1");
            map.put("fileId", fileId);
            if (index != total)
                return map;
        }

        if (path.isDirectory()) {
            File[] fileArray = path.listFiles();
            if (fileArray != null) {
                if (fileArray.length == total) {
                    //分块全部上传完毕,合并

                    File newFile = new File(saveDirectory, fileId + "." + suffix);
                    FileOutputStream outputStream = new FileOutputStream(newFile, true);//文件追加写入
                    byte[] byt = new byte[Byte.valueOf(size) * 1024 * 1024];
                    int len;
                    FileInputStream temp = null;//分片文件
                    for (int i = 0; i < total; i++) {
                        int j = i + 1;
                        temp = new FileInputStream(new File(saveDirectory, fileId + "_" + j));
                        while ((len = temp.read(byt)) != -1) {
                            outputStream.write(byt, 0, len);
                        }
                    }
                    //关闭流
                    temp.close();
                    outputStream.close();
                    System.gc();
                    Runtime.getRuntime().runFinalization();
                    System.gc();


                    map = new HashMap<>();
                    map.put("fileId", fileId);
                    map.put("flag", "2");

                    // 上传成功后删除分片文件
                    File files = new File(saveDirectory);
                    delPieceFile(files);

                    return map;
                }
            }
        }
        return map;
    }

    private static void delPieceFile(File f) {
        //数组指向文件夹中的文件和文件夹
        File[] fi = f.listFiles();
        //遍历文件和文件夹
        assert fi != null;
        for (File file : fi) {
            //如果是文件夹，递归查找
            if (file.isFile()) {
                String filename = file.getName();
                if (filename.contains("_")) {
                    file.delete();
                }
            }
        }
    }

}
